using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Text;
using ConfigurationSettings;
using FileSystemControls.ListViewItems;
using FileSystemControls.Support;

//For getting the small icon

namespace FileSystemControls
{
    [System.ComponentModel.DesignerCategory("Code")]
    public class FileSystemListViewItem : ListViewItem, IDisposable
    {
        public virtual event EventHandler<CopyProgressEventArgs> CopyProgress;
        public virtual event EventHandler CopyComplete;

        //[DllImport("kernel32")]
        //protected static extern int DeviceIoControl(IntPtr hDevice, int dwIoControlCode,
        //    ref short lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize,
        //    ref int lpBytesReturned, IntPtr lpOverlapped);


        #region ** Member Variables **

        bool _disposed = false;

        /// <summary>
        /// Size of the item if it's a file.
        /// </summary>
        protected long _fileLength = -1;

        /// <summary>
        /// Full path and filename.
        /// </summary>
        protected string _fullPath = String.Empty;

        /// <summary>
        /// Date file was created
        /// </summary>
        protected DateTime _createDate;

        /// <summary>
        /// Date file was modified
        /// </summary>
        protected DateTime _modifyDate;

        /// <summary>
        /// Internal flag noting whether this file is readonly.
        /// </summary>
        protected bool _isReadOnly = true;

        /// <summary>
        /// Internal flag noting whether this file is hidden.
        /// </summary>
        protected bool _isHidden = true;

        /// <summary>
        /// Internal flag noting whether this file is redy for archiving.
        /// </summary>
        protected bool _isArchive = true;

        /// <summary>
        /// Internal flag noting whether this file is compressed.
        /// </summary>
        protected bool _isCompressed = true;

        /// <summary>
        /// Internal flag noting whether this file is encrypted.
        /// </summary>
        protected bool _isEncrypted = true;

        /// <summary>
        /// Internal flag noting whether this file is encrypted.
        /// </summary>
        protected bool _isDevice = true;

        /// <summary>
        /// Internal flag noting whether this file is marked.
        /// </summary>
        protected bool _isMarked = false;

        /// <summary>
        /// Internal flag noting whether this item is a File.
        /// </summary>
        protected bool _isFile = false;

        /// <summary>
        /// Internal flag noting whether this is a System file.
        /// </summary>
        protected bool _isSystem = false;

        /// <summary>
        /// Internal flag noting whether this file is currently offline.
        /// </summary>
        protected bool _isOffline = false;

        /// <summary>
        /// Internal flag noting whether this is the DotDot entry used for navigation.
        /// </summary>
        //protected bool _isDotDot = false;

        protected FileSystemInfo _thisObject;

        /// <summary>
        /// Internal flag representing the unit the size will be reported in.
        /// </summary>
        protected SizeUnitType _fileSizeType = SizeUnitType.Bytes;

        /// <summary>
        /// Internal representation used to find the length.
        /// </summary>
        protected long _sizeMultiplier = 1024;

        /// <summary>
        /// Internal postfix added to the end of the Length string
        /// </summary>
        protected string _sizePostfix = " Kb";

        /// <summary>
        /// Internal preecision of decimal places to display
        /// </summary>
        protected int _sizePrecision = 2;

        /// <summary>
        /// Internal representation of the files extension.
        /// </summary>
        protected string _extension = "";

        protected string _comments;
        protected string _companyName;
        protected string _fileVersion;
        protected string _internalName;
        protected string _language;
        protected string _legalCopyright;
        protected string _originalFilename;
        protected string _productName;
        protected string _productVersion;
        protected string _assemblyVersion;
        protected string _toolTip;

        protected Icon _smallIcon;

        protected string _fileType;
        protected string _associatedExecutable;

        #endregion

        #region ** Properties **

        /// <summary>
        /// Length of the file this item refers to.
        /// </summary>
        public virtual long Length
        {
            get
            {
                return _fileLength;
            }
        }

        ///// <summary>
        ///// Path to this entry (without file)
        ///// </summary>
        //public string Path
        //{
        //    get
        //    {
        //        return _path;
        //    }
        //}

        /// <summary>
        /// Full Path (including FileName)
        /// </summary>
        public string FullPath
        {
            get
            {
                return _fullPath;
            }
        }

        /// <summary>
        /// Name without extensions
        /// </summary>
        public string RootName { get; set; }

        /// <summary>
        /// Create date for this entry.
        /// </summary>
        public DateTime CreateDate
        {
            get
            {
                return _createDate;
            }
        }

        /// <summary>
        /// Last date the entry was modified.
        /// </summary>
        public DateTime ModifyDate
        {
            get
            {
                return _modifyDate;
            }
        }

        public bool IsMarked
        {
            get
            {
                return _isMarked;
            }
            set
            {
                _isMarked = value;
            }
        }

        //public bool IsMouseOver
        //{
        //    get
        //    {
        //        return _isMouseOver;
        //    }
        //    set
        //    {
        //        _isMouseOver = value;
        //    }
        //}

        public virtual bool IsReadOnly
        {
            get
            {
                return _isReadOnly;
            }
        }

        public virtual bool IsHidden
        {
            get
            {
                return _isHidden;
            }
        }

        public virtual bool IsArchive
        {
            get
            {
                return _isArchive;
            }
        }

        public virtual bool IsSystem
        {
            get { return _isSystem; }
        }

        public virtual bool IsCompressed
        {
            get { return _isCompressed; }
        }

        public virtual bool IsEncrypted
        {
            get
            {
                return _isEncrypted;
            }
        }

        public bool IsOffline
        {
            get
            {
                return _isOffline;
            }
        }

        public bool IsDevice
        {
            get
            {
                return _isDevice;
            }
        }

        //public bool IsDotDot
        //{
        //    get
        //    {
        //        return _isDotDot;
        //    }
        //}

        public virtual SizeUnitType FileSizeType
        {
            get
            {
                return _fileSizeType;
            }
            set
            {
                _fileSizeType = value;
            }
        }

        public int SizePrecision
        {
            get
            {
                return _sizePrecision;
            }
            set
            {
                _sizePrecision = value;
            }
        }

        public string Extension
        {
            get
            {
                return _extension;
            }
        }

        //public string Description
        //{
        //    get
        //    {
        //        return _fileDescription;
        //    }
        //}

        public string Comments
        {
            get
            {
                return _comments;
            }
        }

        public string CompanyName
        {
            get
            {
                return _companyName;
            }
        }

        public string FileVersion
        {
            get
            {
                return _fileVersion;
            }
        }

        public string InternalName
        {
            get
            {
                return _internalName;
            }
        }

        public string Language
        {
            get
            {
                return _language;
            }
        }

        public string LegalCopyright
        {
            get
            {
                return _legalCopyright;
            }
        }

        public string OriginalFilename
        {
            get
            {
                return _originalFilename;
            }
        }

        public string ProductName
        {
            get
            {
                return _productName;
            }
        }

        public string ProductVersion
        {
            get
            {
                return _productVersion;
            }
        }

        public string ToolTip
        {
            get
            {
                return _toolTip;
            }
        }

        public Icon SmallIcon
        {
            get
            {
                return _smallIcon;
            }
        }

        public string FileType
        {
            get
            {
                return _fileType;
            }
        }

        public string AssociatedExecutable
        {
            get
            {
                return _associatedExecutable;
            }
        }

        public bool IsMouseOver { get; set; }
        public string Path { get; protected set; }

        #endregion

        #region ** Constructors **

        /// <summary>
        /// Protected object constructor used to initialize member variables.
        /// </summary>
        protected FileSystemListViewItem()
        {
            IsMouseOver = false;
            RootName = String.Empty;
            Path = String.Empty;
        }

        /// <summary>
        /// Initializes a new instance of the FileSystemListViewItem object using Text as the display text.
        /// </summary>
        /// <param name="argText">Text to display in the item.</param>
        public FileSystemListViewItem(string argText)
            : this()
        {
            this.Text = argText;
        }

        //public FileSystemListViewItem(FileSystemInfo CurrentEntry, bool IsDotDot)
        //    : this()
        //{
        //}

        public void Dispose()
        {
            Dispose(false);

            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool FinalizerDisposing)
        {
            if (!this._disposed)
            {
                if (FinalizerDisposing)
                {
                    return;
                }

                if (_smallIcon != null)
                {
                    NativeMethods.DestroyIcon(_smallIcon.Handle);
                    _smallIcon.Dispose();
                    _smallIcon = null;
                }

                //if (_largeIcon != null)
                //{
                //    Win32.DestroyIcon(_largeIcon.Handle);
                //    _largeIcon.Dispose();
                //    _largeIcon = null;
                //}

                //DO NOT DISPOSE OF THINGS YOU DON'T CREATE!!!
                //this.Font.Dispose();

                _disposed = true;
            }
        }

        ~FileSystemListViewItem()
        {
            Dispose(true);
        }

        #endregion

        #region ** Protected Methods **
            
        protected virtual void OnCopyProgress(long FilePoition)
        {
            CopyProgress.Raise(this, new CopyProgressEventArgs(FilePoition));
        }

        protected virtual void OnCopyComplete()
        {
            CopyComplete.Raise(this, new EventArgs());
        }

        protected string GetSizeText(decimal FileLength, SizeUnitType SizePostfix)
        {
            string ReturnText = String.Empty;

            if (Math.Round(FileLength, 0) > 0)
            {
                ReturnText = GetSizeText(FileLength / 1024, (SizeUnitType)((int)SizePostfix) + 1);
            }

            return ReturnText;
        }

        /// <summary>
        /// Copies a directory from one location to another.
        /// </summary>
        /// <param name="SourceDirectory">The source location.</param>
        /// <param name="DestinationDirectory">The destination location.</param>
        /// <param name="ForceAction">Force the copy to take place regardless of ReadOnly attributes.</param>
        protected void CopyDir(DirectoryInfo SourceDirectory, DirectoryInfo DestinationDirectory, bool ForceAction)
        {
            string DestinationFileName;

            //Get list of subdirs before adding new subdir 
            DirectoryInfo[] SubDirList = SourceDirectory.GetDirectories();

            //Create Destination directory
            if (DestinationDirectory.Exists)
            {
                CopyDir(SourceDirectory, new DirectoryInfo(DestinationDirectory.Parent.FullName + "\\Duplicate of " + DestinationDirectory.Name), ForceAction);
                return;
            }

            DestinationDirectory.Create();

            //Copy FileList from SourceDir to DestinationDir/SourceSub
            foreach (FileInfo CurrentFile in SourceDirectory.GetFiles())
            {
                DestinationFileName = DestinationDirectory.FullName + "\\" + CurrentFile.Name;
                FileInfo NewFile = new FileInfo(DestinationFileName);
                if (NewFile.Exists && !ForceAction)
                {
                    throw new FileAlreadyExistsException(NewFile);
                }

                CurrentFile.CopyTo(DestinationFileName);
            }
            //Get list of SourceSubDirs
            foreach (DirectoryInfo SourceSubDir in SubDirList)
            {
                //Loop through SourceSubdirs and call CopyDir for each
                CopyDir(SourceSubDir, DestinationDirectory, ForceAction);
            }
        }

        protected void DeleteDir(DirectoryInfo CurrentDirectory, bool ForceAction)
        {
            foreach (FileInfo CurrentFile in CurrentDirectory.GetFiles())
            {
                if (!ForceAction && (CurrentFile.Attributes & FileAttributes.System) == FileAttributes.System)
                {
                    throw new FileIsSystemException(CurrentFile);
                }

                if (!ForceAction && CurrentFile.IsReadOnly)
                {
                    throw new FileIsReadOnlyException(CurrentFile);
                }

                if (!ForceAction && (CurrentFile.Attributes & FileAttributes.Offline) == FileAttributes.Offline)
                {
                    throw new FileIsOfflineException(CurrentFile);
                }

                CurrentFile.IsReadOnly = false;

                CurrentFile.Delete();
            }

            foreach (DirectoryInfo SubDir in CurrentDirectory.GetDirectories())
            {
                DeleteDir(SubDir, ForceAction);
            }

            CurrentDirectory.Attributes = FileAttributes.Directory;
            CurrentDirectory.Delete();

        }

        #endregion

        #region ** Public Methods **

        public override string ToString()
        {
            return this.Name;
        }

        public virtual void Refresh()
        {
            throw new ApplicationException("Base class accessed for Refresh. Please debug the issue.");
        }

        public virtual void Rename(string argNewName)
        {
            throw new ApplicationException("Base class accessed for Rename(string NewName). Please debug the issue.");
        }

        public virtual void Rename(string argNewName, bool argForceAction)
        {
            throw new ApplicationException("Base class accessed for Rename(string NewName, bool ForceAction). Please debug the issue.");
        }

        //public virtual void CopyTo(string DestinationPath, ProgressBarEx CurrentProgressBar)
        //{
        //}

        //public virtual void CopyTo(string DestinationPath, ProgressBarEx CurrentProgressBar, EmptyMethodCallback CallbackMethod)
        //{
        //}

        //public virtual void CopyTo(string DestinationPath, ProgressBarEx CurrentProgressBar, Predicate<long> ProgressMethod)
        //{
        //}
        public virtual void CopyTo(string argNewPath, bool argForceAction = false) { }

        public virtual void CopyCancel() { }
        

        #endregion

        public FileListViewItem ToFileListViewItem()
        {
            var localFileInfo = new FileInfo(this.FullPath);
            return new FileListViewItem(localFileInfo);
        }
    }

    //[StructLayout(LayoutKind.Sequential)]
    //public struct SHFILEINFO
    //{
    //    public IntPtr hIcon;
    //    public IntPtr iIcon;
    //    public uint dwAttributes;
    //    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    //    public string szDisplayName;
    //    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    //    public string szTypeName;
    //};

    //public class Win32
    //{
    //    public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
    //    public const uint SHGFI_SMALLICON = 0x1; // 'Small icon
    //    public const uint SHGFI_ICON = 0x100;
    //    public const uint SHGFI_TYPENAME = 0x400;
    //    public const uint SHGFI_DISPLAYNAME = 0x200;
    //    public const uint SHGFI_EXETYPE = 0x2000;


    //}

}
